/******************************************************************************* * Copyright (c) 2000, 2011 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.jdt.internal.corext.refactoring.structure.constraints; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Stack; import org.eclipse.core.runtime.Assert; import org.eclipse.jdt.core.SourceRange; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration; import org.eclipse.jdt.core.dom.AnonymousClassDeclaration; import org.eclipse.jdt.core.dom.ArrayAccess; import org.eclipse.jdt.core.dom.ArrayCreation; import org.eclipse.jdt.core.dom.ArrayInitializer; import org.eclipse.jdt.core.dom.ArrayType; import org.eclipse.jdt.core.dom.Assignment; import org.eclipse.jdt.core.dom.CastExpression; import org.eclipse.jdt.core.dom.CatchClause; import org.eclipse.jdt.core.dom.ClassInstanceCreation; import org.eclipse.jdt.core.dom.Comment; import org.eclipse.jdt.core.dom.ConditionalExpression; import org.eclipse.jdt.core.dom.ConstructorInvocation; import org.eclipse.jdt.core.dom.EnhancedForStatement; import org.eclipse.jdt.core.dom.Expression; import org.eclipse.jdt.core.dom.FieldAccess; import org.eclipse.jdt.core.dom.FieldDeclaration; import org.eclipse.jdt.core.dom.IBinding; import org.eclipse.jdt.core.dom.IMethodBinding; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.IVariableBinding; import org.eclipse.jdt.core.dom.ImportDeclaration; import org.eclipse.jdt.core.dom.InstanceofExpression; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.MethodInvocation; import org.eclipse.jdt.core.dom.Name; import org.eclipse.jdt.core.dom.NullLiteral; import org.eclipse.jdt.core.dom.PackageDeclaration; import org.eclipse.jdt.core.dom.ParenthesizedExpression; import org.eclipse.jdt.core.dom.QualifiedName; import org.eclipse.jdt.core.dom.ReturnStatement; import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.dom.SingleVariableDeclaration; import org.eclipse.jdt.core.dom.SuperConstructorInvocation; import org.eclipse.jdt.core.dom.SuperFieldAccess; import org.eclipse.jdt.core.dom.SuperMethodInvocation; import org.eclipse.jdt.core.dom.ThisExpression; import org.eclipse.jdt.core.dom.Type; import org.eclipse.jdt.core.dom.TypeLiteral; import org.eclipse.jdt.core.dom.VariableDeclarationExpression; import org.eclipse.jdt.core.dom.VariableDeclarationFragment; import org.eclipse.jdt.core.dom.VariableDeclarationStatement; import org.eclipse.jdt.internal.corext.dom.Bindings; import org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor; import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.CompilationUnitRange; import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ConstraintVariable2; import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser; /** * Type constraints creator to determine the necessary constraints to replace type occurrences by a given super type. * * @since 3.1 */ public final class SuperTypeConstraintsCreator extends HierarchicalASTVisitor { /** The constraint variable property */ private static final String PROPERTY_CONSTRAINT_VARIABLE= "cv"; //$NON-NLS-1$ /** * Returns the original methods of the method hierarchy of the specified method. * * @param binding the method binding * @param type the current type * @param originals the original methods which have already been found (element type: <code>IMethodBinding</code>) * @param implementations <code>true</code> to favor implementation methods, <code>false</code> otherwise */ private static void getOriginalMethods(final IMethodBinding binding, final ITypeBinding type, final Collection<IMethodBinding> originals, final boolean implementations) { final ITypeBinding ancestor= type.getSuperclass(); if (!implementations) { final ITypeBinding[] types= type.getInterfaces(); for (int index= 0; index < types.length; index++) getOriginalMethods(binding, types[index], originals, implementations); if (ancestor != null) getOriginalMethods(binding, ancestor, originals, implementations); } if (implementations && ancestor != null) getOriginalMethods(binding, ancestor, originals, implementations); final IMethodBinding[] methods= type.getDeclaredMethods(); IMethodBinding method= null; for (int index= 0; index < methods.length; index++) { method= methods[index]; if (!binding.getKey().equals(method.getKey())) { boolean match= false; IMethodBinding current= null; for (final Iterator<IMethodBinding> iterator= originals.iterator(); iterator.hasNext();) { current= iterator.next(); if (Bindings.isSubsignature(method, current)) match= true; } if (!match && Bindings.isSubsignature(binding, method)) originals.add(method); } } } /** The current method declarations being processed (element type: <code>MethodDeclaration</code>) */ private final Stack<MethodDeclaration> fCurrentMethods= new Stack<MethodDeclaration>(); /** Should instanceof expressions be rewritten? */ private final boolean fInstanceOf; /** The type constraint model to solve */ private final SuperTypeConstraintsModel fModel; /** * Creates a new super type constraints creator. * * @param model the model to create the type constraints for * @param instanceofs <code>true</code> to rewrite instanceof expressions, <code>false</code> otherwise */ public SuperTypeConstraintsCreator(final SuperTypeConstraintsModel model, final boolean instanceofs) { Assert.isNotNull(model); fModel= model; fInstanceOf= instanceofs; } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.jdt.core.dom.ArrayAccess) */ @Override public final void endVisit(final ArrayAccess node) { node.setProperty(PROPERTY_CONSTRAINT_VARIABLE, node.getArray().getProperty(PROPERTY_CONSTRAINT_VARIABLE)); } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.jdt.core.dom.ArrayCreation) */ @Override public final void endVisit(final ArrayCreation node) { final ConstraintVariable2 ancestor= (ConstraintVariable2) node.getType().getProperty(PROPERTY_CONSTRAINT_VARIABLE); node.setProperty(PROPERTY_CONSTRAINT_VARIABLE, ancestor); final ArrayInitializer initializer= node.getInitializer(); if (initializer != null) { final ConstraintVariable2 descendant= (ConstraintVariable2) initializer.getProperty(PROPERTY_CONSTRAINT_VARIABLE); if (descendant != null) fModel.createSubtypeConstraint(descendant, ancestor); } } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.jdt.core.dom.ArrayInitializer) */ @Override public final void endVisit(final ArrayInitializer node) { final ITypeBinding binding= node.resolveTypeBinding(); if (binding != null && binding.isArray()) { final ConstraintVariable2 ancestor= fModel.createIndependentTypeVariable(binding.getElementType()); node.setProperty(PROPERTY_CONSTRAINT_VARIABLE, ancestor); Expression expression= null; ConstraintVariable2 descendant= null; final List<Expression> expressions= node.expressions(); for (int index= 0; index < expressions.size(); index++) { expression= expressions.get(index); descendant= (ConstraintVariable2) expression.getProperty(PROPERTY_CONSTRAINT_VARIABLE); if (descendant != null) fModel.createSubtypeConstraint(descendant, ancestor); } } } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.jdt.core.dom.ArrayType) */ @Override public final void endVisit(final ArrayType node) { Type elementType= node.getElementType(); final ConstraintVariable2 variable= fModel.createTypeVariable(elementType); if (variable != null) { elementType.setProperty(PROPERTY_CONSTRAINT_VARIABLE, variable); node.setProperty(PROPERTY_CONSTRAINT_VARIABLE, variable); } } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.jdt.core.dom.Assignment) */ @Override public final void endVisit(final Assignment node) { final ConstraintVariable2 ancestor= (ConstraintVariable2) node.getLeftHandSide().getProperty(PROPERTY_CONSTRAINT_VARIABLE); final ConstraintVariable2 descendant= (ConstraintVariable2) node.getRightHandSide().getProperty(PROPERTY_CONSTRAINT_VARIABLE); node.setProperty(PROPERTY_CONSTRAINT_VARIABLE, ancestor); if (ancestor != null && descendant != null) fModel.createSubtypeConstraint(descendant, ancestor); } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.jdt.core.dom.CastExpression) */ @Override public final void endVisit(final CastExpression node) { final ConstraintVariable2 first= (ConstraintVariable2) node.getType().getProperty(PROPERTY_CONSTRAINT_VARIABLE); if (first != null) { node.setProperty(PROPERTY_CONSTRAINT_VARIABLE, first); final ConstraintVariable2 second= (ConstraintVariable2) node.getExpression().getProperty(PROPERTY_CONSTRAINT_VARIABLE); if (second != null) fModel.createCastVariable(node, second); } } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.jdt.core.dom.CatchClause) */ @Override public final void endVisit(final CatchClause node) { final SingleVariableDeclaration declaration= node.getException(); if (declaration != null) { final ConstraintVariable2 descendant= (ConstraintVariable2) declaration.getProperty(PROPERTY_CONSTRAINT_VARIABLE); if (descendant != null) { final ITypeBinding binding= node.getAST().resolveWellKnownType("java.lang.Throwable"); //$NON-NLS-1$ if (binding != null) { final ConstraintVariable2 ancestor= fModel.createImmutableTypeVariable(binding); if (ancestor != null) fModel.createSubtypeConstraint(descendant, ancestor); } } } } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.jdt.core.dom.ClassInstanceCreation) */ @Override public final void endVisit(final ClassInstanceCreation node) { final IMethodBinding binding= node.resolveConstructorBinding(); if (binding != null) { endVisit(node.arguments(), binding); ConstraintVariable2 variable= null; final AnonymousClassDeclaration declaration= node.getAnonymousClassDeclaration(); if (declaration != null) { final ITypeBinding type= declaration.resolveBinding(); if (type != null) variable= fModel.createImmutableTypeVariable(type); } else { final ITypeBinding type= node.resolveTypeBinding(); if (type != null) variable= fModel.createImmutableTypeVariable(type); } if (variable != null) node.setProperty(PROPERTY_CONSTRAINT_VARIABLE, variable); } } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.jdt.core.dom.ConditionalExpression) */ @Override public final void endVisit(final ConditionalExpression node) { ConstraintVariable2 thenVariable= null; ConstraintVariable2 elseVariable= null; final Expression thenExpression= node.getThenExpression(); if (thenExpression != null) thenVariable= (ConstraintVariable2) thenExpression.getProperty(PROPERTY_CONSTRAINT_VARIABLE); final Expression elseExpression= node.getElseExpression(); if (elseExpression != null) elseVariable= (ConstraintVariable2) elseExpression.getProperty(PROPERTY_CONSTRAINT_VARIABLE); ITypeBinding binding= node.resolveTypeBinding(); if (binding != null) { if (binding.isArray()) binding= binding.getElementType(); final ConstraintVariable2 ancestor= fModel.createIndependentTypeVariable(binding); if (ancestor != null) { node.setProperty(PROPERTY_CONSTRAINT_VARIABLE, ancestor); if (thenVariable != null) fModel.createSubtypeConstraint(thenVariable, ancestor); if (elseVariable != null) fModel.createSubtypeConstraint(elseVariable, ancestor); if (thenVariable != null && elseVariable != null) fModel.createConditionalTypeConstraint(ancestor, thenVariable, elseVariable); } } } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.jdt.core.dom.ConstructorInvocation) */ @Override public final void endVisit(final ConstructorInvocation node) { final IMethodBinding binding= node.resolveConstructorBinding(); if (binding != null) endVisit(node.arguments(), binding); } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.jdt.core.dom.FieldAccess) */ @Override public final void endVisit(final FieldAccess node) { final IVariableBinding binding= node.resolveFieldBinding(); if (binding != null) endVisit(binding, node.getExpression(), node); } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.jdt.core.dom.FieldDeclaration) */ @Override public final void endVisit(final FieldDeclaration node) { endVisit(node.fragments(), node.getType(), node); } /** * End of visit the specified method declaration. * * @param binding the method binding */ private void endVisit(final IMethodBinding binding) { IMethodBinding method= null; ConstraintVariable2 ancestor= null; final ConstraintVariable2 descendant= fModel.createReturnTypeVariable(binding); if (descendant != null) { final Collection<IMethodBinding> originals= getOriginalMethods(binding); for (final Iterator<IMethodBinding> iterator= originals.iterator(); iterator.hasNext();) { method= iterator.next(); if (!method.getKey().equals(binding.getKey())) { ancestor= fModel.createReturnTypeVariable(method); if (ancestor != null) fModel.createCovariantTypeConstraint(descendant, ancestor); } } } } /** * End of visit the specified method invocation. * * @param binding the method binding * @param descendant the constraint variable of the invocation expression */ private void endVisit(final IMethodBinding binding, final ConstraintVariable2 descendant) { ITypeBinding declaring= null; IMethodBinding method= null; final Collection<IMethodBinding> originals= getOriginalMethods(binding); for (final Iterator<IMethodBinding> iterator= originals.iterator(); iterator.hasNext();) { method= iterator.next(); declaring= method.getDeclaringClass(); if (declaring != null) { final ConstraintVariable2 ancestor= fModel.createDeclaringTypeVariable(declaring); if (ancestor != null) fModel.createSubtypeConstraint(descendant, ancestor); } } } /** * End of visit the thrown exception * * @param binding the type binding of the thrown exception * @param node the exception name node */ private void endVisit(final ITypeBinding binding, final Name node) { final ConstraintVariable2 variable= fModel.createExceptionVariable(node); if (variable != null) node.setProperty(PROPERTY_CONSTRAINT_VARIABLE, variable); } /** * End of visit the field access. * * @param binding the variable binding * @param qualifier the qualifier expression, or <code>null</code> * @param access the access expression */ private void endVisit(final IVariableBinding binding, final Expression qualifier, final Expression access) { access.setProperty(PROPERTY_CONSTRAINT_VARIABLE, fModel.createVariableVariable(binding)); if (qualifier != null) { final ITypeBinding type= binding.getDeclaringClass(); if (type != null) { // array.length does not have a declaring class final ConstraintVariable2 ancestor= fModel.createDeclaringTypeVariable(type); if (ancestor != null) { final ConstraintVariable2 descendant= (ConstraintVariable2) qualifier.getProperty(PROPERTY_CONSTRAINT_VARIABLE); if (descendant != null) fModel.createSubtypeConstraint(descendant, ancestor); } } } } /** * End of visit the method argument list. * * @param arguments the arguments (element type: <code>Expression</code>) * @param binding the method binding */ private void endVisit(final List<Expression> arguments, final IMethodBinding binding) { Expression expression= null; ConstraintVariable2 ancestor= null; ConstraintVariable2 descendant= null; for (int index= 0; index < arguments.size(); index++) { expression= arguments.get(index); descendant= (ConstraintVariable2) expression.getProperty(PROPERTY_CONSTRAINT_VARIABLE); ancestor= fModel.createMethodParameterVariable(binding, index); if (ancestor != null && descendant != null) fModel.createSubtypeConstraint(descendant, ancestor); } } /** * End of visit the variable declaration fragment list. * * @param fragments the fragments (element type: <code>VariableDeclarationFragment</code>) * @param type the type of the fragments * @param parent the parent of the fragment list */ private void endVisit(final List<VariableDeclarationFragment> fragments, final Type type, final ASTNode parent) { final ConstraintVariable2 ancestor= (ConstraintVariable2) type.getProperty(PROPERTY_CONSTRAINT_VARIABLE); if (ancestor != null) { IVariableBinding binding= null; ConstraintVariable2 descendant= null; VariableDeclarationFragment fragment= null; for (int index= 0; index < fragments.size(); index++) { fragment= fragments.get(index); descendant= (ConstraintVariable2) fragment.getProperty(PROPERTY_CONSTRAINT_VARIABLE); if (descendant != null) fModel.createSubtypeConstraint(descendant, ancestor); binding= fragment.resolveBinding(); if (binding != null) { descendant= fModel.createVariableVariable(binding); if (descendant != null) fModel.createEqualityConstraint(ancestor, descendant); } } parent.setProperty(PROPERTY_CONSTRAINT_VARIABLE, ancestor); } } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.jdt.core.dom.MethodDeclaration) */ @Override public final void endVisit(final MethodDeclaration node) { fCurrentMethods.pop(); final IMethodBinding binding= node.resolveBinding(); if (binding != null) { if (!binding.isConstructor()) { final Type type= node.getReturnType2(); if (type != null) { final ConstraintVariable2 first= fModel.createReturnTypeVariable(binding); final ConstraintVariable2 second= (ConstraintVariable2) type.getProperty(PROPERTY_CONSTRAINT_VARIABLE); if (first != null) { if (second != null) fModel.createEqualityConstraint(first, second); endVisit(binding); } } } ConstraintVariable2 ancestor= null; ConstraintVariable2 descendant= null; IVariableBinding variable= null; final List<SingleVariableDeclaration> parameters= node.parameters(); if (!parameters.isEmpty()) { final Collection<IMethodBinding> originals= getOriginalMethods(binding); SingleVariableDeclaration declaration= null; for (int index= 0; index < parameters.size(); index++) { declaration= parameters.get(index); ancestor= fModel.createMethodParameterVariable(binding, index); if (ancestor != null) { descendant= (ConstraintVariable2) declaration.getType().getProperty(PROPERTY_CONSTRAINT_VARIABLE); if (descendant != null) fModel.createEqualityConstraint(descendant, ancestor); variable= declaration.resolveBinding(); if (variable != null) { descendant= fModel.createVariableVariable(variable); if (descendant != null) fModel.createEqualityConstraint(ancestor, descendant); } IMethodBinding method= null; for (final Iterator<IMethodBinding> iterator= originals.iterator(); iterator.hasNext();) { method= iterator.next(); if (!method.getKey().equals(binding.getKey())) { descendant= fModel.createMethodParameterVariable(method, index); if (descendant != null) fModel.createEqualityConstraint(ancestor, descendant); } } } } } final List<Name> exceptions= node.thrownExceptions(); if (!exceptions.isEmpty()) { final ITypeBinding throwable= node.getAST().resolveWellKnownType("java.lang.Throwable"); //$NON-NLS-1$ if (throwable != null) { ancestor= fModel.createImmutableTypeVariable(throwable); if (ancestor != null) { Name exception= null; for (int index= 0; index < exceptions.size(); index++) { exception= exceptions.get(index); descendant= (ConstraintVariable2) exception.getProperty(PROPERTY_CONSTRAINT_VARIABLE); if (descendant != null) fModel.createSubtypeConstraint(descendant, ancestor); } } } } } } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.jdt.core.dom.MethodInvocation) */ @Override public final void endVisit(final MethodInvocation node) { final IMethodBinding binding= node.resolveMethodBinding(); if (binding != null) { endVisit(node, binding); endVisit(node.arguments(), binding); final Expression expression= node.getExpression(); if (expression != null) { final ConstraintVariable2 descendant= (ConstraintVariable2) expression.getProperty(PROPERTY_CONSTRAINT_VARIABLE); if (descendant != null) endVisit(binding, descendant); } } } /** * End of visit the return type of a method invocation. * * @param invocation the method invocation * @param binding the method binding */ private void endVisit(final MethodInvocation invocation, final IMethodBinding binding) { if (!binding.isConstructor()) { final ConstraintVariable2 variable= fModel.createReturnTypeVariable(binding); if (variable != null) invocation.setProperty(PROPERTY_CONSTRAINT_VARIABLE, variable); } } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.jdt.core.dom.NullLiteral) */ @Override public final void endVisit(final NullLiteral node) { node.setProperty(PROPERTY_CONSTRAINT_VARIABLE, fModel.createImmutableTypeVariable(node.resolveTypeBinding())); } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.jdt.core.dom.ParenthesizedExpression) */ @Override public final void endVisit(final ParenthesizedExpression node) { node.setProperty(PROPERTY_CONSTRAINT_VARIABLE, node.getExpression().getProperty(PROPERTY_CONSTRAINT_VARIABLE)); } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.jdt.core.dom.QualifiedName) */ @Override public final void endVisit(final QualifiedName node) { final ASTNode parent= node.getParent(); final Name qualifier= node.getQualifier(); IBinding binding= qualifier.resolveBinding(); if (binding instanceof ITypeBinding) { final ConstraintVariable2 variable= fModel.createTypeVariable((ITypeBinding) binding, new CompilationUnitRange(RefactoringASTParser.getCompilationUnit(node), new SourceRange(qualifier.getStartPosition(), qualifier.getLength()))); if (variable != null) qualifier.setProperty(PROPERTY_CONSTRAINT_VARIABLE, variable); } binding= node.getName().resolveBinding(); if (binding instanceof IVariableBinding && !(parent instanceof ImportDeclaration)) endVisit((IVariableBinding) binding, qualifier, node); else if (binding instanceof ITypeBinding && parent instanceof MethodDeclaration) endVisit((ITypeBinding) binding, node); } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.jdt.core.dom.ReturnStatement) */ @Override public final void endVisit(final ReturnStatement node) { final Expression expression= node.getExpression(); if (expression != null) { final ConstraintVariable2 descendant= (ConstraintVariable2) expression.getProperty(PROPERTY_CONSTRAINT_VARIABLE); if (descendant != null) { final MethodDeclaration declaration= fCurrentMethods.peek(); if (declaration != null) { final IMethodBinding binding= declaration.resolveBinding(); if (binding != null) { final ConstraintVariable2 ancestor= fModel.createReturnTypeVariable(binding); if (ancestor != null) { node.setProperty(PROPERTY_CONSTRAINT_VARIABLE, ancestor); fModel.createSubtypeConstraint(descendant, ancestor); } } } } } } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.jdt.core.dom.SimpleName) */ @Override public final void endVisit(final SimpleName node) { final ASTNode parent= node.getParent(); if (!(parent instanceof ImportDeclaration) && !(parent instanceof PackageDeclaration) && !(parent instanceof AbstractTypeDeclaration)) { final IBinding binding= node.resolveBinding(); if (binding instanceof IVariableBinding && !(parent instanceof MethodDeclaration)) endVisit((IVariableBinding) binding, null, node); else if (binding instanceof ITypeBinding && parent instanceof MethodDeclaration) endVisit((ITypeBinding) binding, node); } } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.jdt.core.dom.SingleVariableDeclaration) */ @Override public final void endVisit(final SingleVariableDeclaration node) { final ConstraintVariable2 ancestor= (ConstraintVariable2) node.getType().getProperty(PROPERTY_CONSTRAINT_VARIABLE); if (ancestor != null) { node.setProperty(PROPERTY_CONSTRAINT_VARIABLE, ancestor); final Expression expression= node.getInitializer(); if (expression != null) { final ConstraintVariable2 descendant= (ConstraintVariable2) expression.getProperty(PROPERTY_CONSTRAINT_VARIABLE); if (descendant != null) fModel.createSubtypeConstraint(descendant, ancestor); } } } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.jdt.core.dom.EnhancedForStatement) */ @Override public void endVisit(EnhancedForStatement node) { SingleVariableDeclaration parameter= node.getParameter(); final ConstraintVariable2 ancestor= (ConstraintVariable2) parameter.getType().getProperty(PROPERTY_CONSTRAINT_VARIABLE); if (ancestor != null) { IVariableBinding binding= parameter.resolveBinding(); if (binding != null) { ConstraintVariable2 descendant= fModel.createVariableVariable(binding); if (descendant != null) { fModel.createEqualityConstraint(ancestor, descendant); } } ITypeBinding collectionType= node.getExpression().resolveTypeBinding(); if (collectionType != null && collectionType.isArray()) { ConstraintVariable2 descendant= (ConstraintVariable2) node.getExpression().getProperty(PROPERTY_CONSTRAINT_VARIABLE); if (descendant != null) { fModel.createSubtypeConstraint(descendant, ancestor); } } } } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.jdt.core.dom.SuperConstructorInvocation) */ @Override public final void endVisit(final SuperConstructorInvocation node) { final IMethodBinding binding= node.resolveConstructorBinding(); if (binding != null) endVisit(node.arguments(), binding); } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.jdt.core.dom.SuperFieldAccess) */ @Override public final void endVisit(final SuperFieldAccess node) { final Name name= node.getName(); final IBinding binding= name.resolveBinding(); if (binding instanceof IVariableBinding) endVisit((IVariableBinding) binding, null, node); } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.jdt.core.dom.SuperMethodInvocation) */ @Override public final void endVisit(final SuperMethodInvocation node) { final IMethodBinding superBinding= node.resolveMethodBinding(); if (superBinding != null) { endVisit(node.arguments(), superBinding); final MethodDeclaration declaration= fCurrentMethods.peek(); if (declaration != null) { final IMethodBinding subBinding= declaration.resolveBinding(); if (subBinding != null) { final ConstraintVariable2 ancestor= fModel.createReturnTypeVariable(superBinding); if (ancestor != null) { node.setProperty(PROPERTY_CONSTRAINT_VARIABLE, ancestor); final ConstraintVariable2 descendant= fModel.createReturnTypeVariable(subBinding); if (descendant != null) fModel.createEqualityConstraint(descendant, ancestor); } } } } } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.jdt.core.dom.ThisExpression) */ @Override public final void endVisit(final ThisExpression node) { final ITypeBinding binding= node.resolveTypeBinding(); if (binding != null) node.setProperty(PROPERTY_CONSTRAINT_VARIABLE, fModel.createDeclaringTypeVariable(binding)); } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.jdt.core.dom.Type) */ @Override public final void endVisit(final Type node) { final ASTNode parent= node.getParent(); if (!(parent instanceof AbstractTypeDeclaration) && !(parent instanceof ClassInstanceCreation) && !(parent instanceof TypeLiteral) && (!(parent instanceof InstanceofExpression) || fInstanceOf)) node.setProperty(PROPERTY_CONSTRAINT_VARIABLE, fModel.createTypeVariable(node)); } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.jdt.core.dom.VariableDeclarationExpression) */ @Override public final void endVisit(final VariableDeclarationExpression node) { endVisit(node.fragments(), node.getType(), node); } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.jdt.core.dom.VariableDeclarationFragment) */ @Override public final void endVisit(final VariableDeclarationFragment node) { final Expression initializer= node.getInitializer(); if (initializer != null) node.setProperty(PROPERTY_CONSTRAINT_VARIABLE, initializer.getProperty(PROPERTY_CONSTRAINT_VARIABLE)); } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#endVisit(org.eclipse.jdt.core.dom.VariableDeclarationStatement) */ @Override public final void endVisit(final VariableDeclarationStatement node) { endVisit(node.fragments(), node.getType(), node); } /** * Returns the original methods of the method hierarchy of the specified method. * * @param binding the method binding * @return the original methods (element type: <code>IMethodBinding</code>) */ private Collection<IMethodBinding> getOriginalMethods(final IMethodBinding binding) { final Collection<IMethodBinding> originals= new ArrayList<IMethodBinding>(); final ITypeBinding type= binding.getDeclaringClass(); getOriginalMethods(binding, type, originals, false); getOriginalMethods(binding, type, originals, true); if (originals.isEmpty()) originals.add(binding); return originals; } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#visit(org.eclipse.jdt.core.dom.AnnotationTypeDeclaration) */ @Override public final boolean visit(final AnnotationTypeDeclaration node) { return false; } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#visit(org.eclipse.jdt.core.dom.Comment) */ @Override public final boolean visit(final Comment node) { return false; } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#visit(org.eclipse.jdt.core.dom.ImportDeclaration) */ @Override public final boolean visit(final ImportDeclaration node) { return false; } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#visit(org.eclipse.jdt.core.dom.MethodDeclaration) */ @Override public final boolean visit(final MethodDeclaration node) { fCurrentMethods.push(node); return super.visit(node); } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#visit(org.eclipse.jdt.core.dom.PackageDeclaration) */ @Override public final boolean visit(final PackageDeclaration node) { return false; } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#visit(org.eclipse.jdt.core.dom.ThisExpression) */ @Override public final boolean visit(final ThisExpression node) { return false; } /* * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#visit(org.eclipse.jdt.core.dom.Type) */ @Override public final boolean visit(final Type node) { return false; } }